package com.example.tool.utils;

import com.example.tool.actions.ConfigAction;
import com.example.tool.entity.ConfigDBEntity;
import com.example.tool.entity.ConfigEntity;
import com.example.tool.module.ModuleInformation;
import com.example.tool.ui.SwingUi;
import com.example.tool.window.HToolWindowConfigAction;
import com.intellij.ide.CutProvider;
import com.intellij.ide.projectView.ProjectViewNode;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationAction;
import com.intellij.notification.NotificationGroupManager;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.actionSystem.Presentation;
import com.intellij.openapi.actionSystem.ex.ActionUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
import com.intellij.openapi.vfs.VirtualFileSystem;
import com.intellij.pom.Navigatable;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiManager;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import org.jetbrains.annotations.NotNull;

import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class ActionToolUtil {
  private static final Logger LOG = Logger.getInstance(ActionToolUtil.class);

  public static void showNotification(Project project, NotificationType notificationType, String content) {
    showNotification(project, notificationType, "", content);
  }

  public static void showNotification(Project project, NotificationType notificationType, String title, String content) {
    showNotification(project, notificationType, title, content, new NotificationAction[0]);
  }

  public static void showNotification(Project project, NotificationType notificationType, String content, NotificationAction... notificationActions) {
    showNotification(project, notificationType, "", content, notificationActions);
  }

  /**
   * 显示消息通知
   * @param project             项目对象
   * @param notificationType    消息类型
   * @param title               消息标题
   * @param content             消息内容
   * @param notificationActions 消息点击动作
   */
  public static void showNotification(Project project, NotificationType notificationType, String title, String content, NotificationAction... notificationActions) {
    NotificationGroupManager instance = NotificationGroupManager.getInstance();
    Notification notification = instance.getNotificationGroup("SeeyonTool").createNotification(title, content, notificationType);
    for (NotificationAction notificationAction : notificationActions) {
      notification.addAction(notificationAction);
    }
    notification.notify(project);
  }

  /**
   * 打开项目中的设置项目目录中的忽略文件
   * @param project 项目对象
   */
  public static void showSetting(Project project) {
    ActionToolUtil.showNotification(project, NotificationType.ERROR, ModuleInformation.IDEA_CONFIG_ERR_MSG, new NotificationAction(ModuleInformation.CONFIG) {
      @Override
      public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
        ShowSettingsUtil.getInstance().showSettingsDialog(project, "Editor/File Types");
      }
    });
  }

  /**
   * 消息提示同步配置信息
   * @param project         项目对象
   * @param pluginInstalled 是否已经安装了能同步的插件
   */
  public static void showSync(Project project, boolean pluginInstalled) {
    if (pluginInstalled) {
      ActionToolUtil.showNotification(project, NotificationType.ERROR, ModuleInformation.DEBUG_CONFIG_ERR, ModuleInformation.DEBUG_CONFIG_TIP_MSG);
    } else {
      ActionToolUtil.showNotification(project, NotificationType.ERROR, ModuleInformation.DEBUG_CONFIG_ERR, ModuleInformation.DEBUG_CONFIG_ERR_MSG, new NotificationAction(ModuleInformation.VIEW) {
        @Override
        public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
          ActionToolUtil.openURL("https://plugins.jetbrains.com/plugin/13125-ftp-sftp-webdav-connectivity");
        }
      });
    }
  }

  public static void openURL(String url) {
    if (Desktop.isDesktopSupported()) {
      Desktop desktop = Desktop.getDesktop();
      try {
        desktop.browse(new URI(url));
      } catch (IOException | URISyntaxException e) {
        LOG.info("打开浏览器失败：" + e.getMessage(), e);
      }
    } else {
      LOG.info("不支持桌面。无法打开URL");
    }
  }

  /**
   * 通过项目获取项目中的配置文件信息
   * @param project 项目对象
   * @return 返回配置信息
   */
  public static ConfigEntity getInformation(Project project) throws Exception {
    if (project != null) {
      String basePath = project.getBasePath();
      if (basePath != null) {
        Path path = Path.of(basePath, ".idea", ModuleInformation.MODULE_CONFIG);
        VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByNioFile(path);
        if (virtualFile != null) {
          VirtualFileSystem fileSystem = VirtualFileManager.getInstance().getFileSystem(LocalFileSystem.PROTOCOL);
          if (fileSystem != null && virtualFile.isValid()) {
            byte[] bytes = virtualFile.contentsToByteArray();
            String count = new String(bytes, StandardCharsets.UTF_8).replaceAll("\uFEFF", "");
            return ConfigEntity.init(count);
          }
        }
      }
    }
    return null;
  }

  /**
   * 通过项目获取项目中的配置数据库的文件信息
   * @param project 项目对象
   * @return 返回配置信息
   */
  public static ConfigDBEntity getInformationDB(Project project) throws Exception {
    if (project != null) {
      String basePath = project.getBasePath();
      if (basePath != null) {
        Path path = Path.of(basePath, ".idea", ModuleInformation.MODULE_CONFIG_DB);
        VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByNioFile(path);
        if (virtualFile != null) {
          VirtualFileSystem fileSystem = VirtualFileManager.getInstance().getFileSystem(LocalFileSystem.PROTOCOL);
          if (fileSystem != null && virtualFile.isValid()) {
            byte[] bytes = virtualFile.contentsToByteArray();
            String count = new String(bytes, StandardCharsets.UTF_8).replaceAll("\uFEFF", "");
            return ConfigDBEntity.init(count);
          }
        }
      }
    }
    return null;
  }

  /**
   * 没有seeyon.txt配置文件错误提示
   * @param project 项目对象
   */
  public static void noConfig(Project project) {
    ActionToolUtil.showNotification(project, NotificationType.ERROR, ModuleInformation.NO_CONFIG, new NotificationAction(ModuleInformation.CONFIG) {
      @Override
      public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
        ActionManager actionManager = ActionManager.getInstance();
        AnAction action = actionManager.getAction(ConfigAction.class.getName());
        ActionUtil.invokeAction(action, e.getDataContext(), e.getPlace(), e.getInputEvent(), () -> {
        });
      }
    });
  }

  /**
   * 没有seeyonDB.txt配置文件错误提示
   * @param project 项目对象
   */
  public static void noConfigDB(Project project) {
    ActionToolUtil.showNotification(project, NotificationType.ERROR, ModuleInformation.NO_CONFIG_DB, new NotificationAction(ModuleInformation.CONFIG_DB) {
      @Override
      public void actionPerformed(@NotNull AnActionEvent e, @NotNull Notification notification) {
        ActionManager actionManager = ActionManager.getInstance();
        AnAction action = actionManager.getAction(HToolWindowConfigAction.class.getName());
        ActionUtil.invokeAction(action, e.getDataContext(), e.getPlace(), e.getInputEvent(), () -> {
        });
      }
    });
  }


  /**
   * 判断Action是否显示
   * @param event 对应的Action的AnActionEvent对象
   */
  public static void actionIsVisible(@NotNull AnActionEvent event) {
    Presentation presentation = event.getPresentation();
    DataContext dataContext = event.getDataContext();
    CutProvider provider = getAvailableCutProvider(event);
    Project project = CommonDataKeys.PROJECT.getData(dataContext);
    if (project != null && provider != null) {
      Module[] modules = ModuleManager.getInstance(project).getModules();
      List<VirtualFile> sourceAll = new ArrayList<>();
      Arrays.stream(modules).forEach(module -> {
        ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
        VirtualFile[] sourceRoots = moduleRootManager.getSourceRoots();
        List<VirtualFile> virtualFiles = Arrays.asList(sourceRoots);
        sourceAll.addAll(virtualFiles);
      });
      Navigatable[] componentRef = CommonDataKeys.NAVIGATABLE_ARRAY.getData(dataContext);
      if (null != componentRef && componentRef.length > 0) {
        Object node = componentRef[0];
        if (node instanceof ProjectViewNode) {
          @SuppressWarnings("rawtypes") ProjectViewNode basePsiNode = (ProjectViewNode) componentRef[0];
          VirtualFile virtualFile = basePsiNode.getVirtualFile();
          String selectPath = String.valueOf(virtualFile);
          boolean rest = sourceAll.stream().anyMatch(virtualFileItem -> {
            String prefix = virtualFileItem + "/";
            if (selectPath.startsWith(prefix) && virtualFile != null) {
              String virtualFilePath = virtualFile.getPath();
              File file = new File(virtualFilePath);
              if (file.isFile()) {
                return selectPath.substring(prefix.length()).contains("/");
              } else {
                return true;
              }
            }
            return false;
          });
          presentation.setVisible(project.isOpen() && rest);
          return;
        }
      }
    }
    presentation.setVisible(false);
  }

  private static CutProvider getAvailableCutProvider(@NotNull AnActionEvent e) {
    CutProvider provider = e.getData(PlatformDataKeys.CUT_PROVIDER);
    Project project = e.getProject();
    if (project != null && DumbService.isDumb(project) && !DumbService.isDumbAware(provider)) {
      return null;
    }
    return provider;
  }

  /**
   * 获取项目中选中的文件路径
   * @param anActionEvent 选中事件对象
   */
  public static List<PsiDirectory> actionSelectPath(@NotNull AnActionEvent anActionEvent) {
    Module module = anActionEvent.getData(LangDataKeys.MODULE);
    List<PsiDirectory> selectPsiDirectory = new ArrayList<>();
    // 当前选中的文件路径
    VirtualFile[] virtualFiles = anActionEvent.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY);
    Project project = anActionEvent.getProject();
    if (project != null) {
      PsiManager psiManager = PsiManager.getInstance(project);
      if (module != null && virtualFiles != null) {
        for (VirtualFile virtualFile : virtualFiles) {
          PsiDirectory directory = psiManager.findDirectory(virtualFile);
          if (directory == null) {
            VirtualFile parent = virtualFile.getParent();
            PsiDirectory parentPsiDirectory = psiManager.findDirectory(parent);
            selectPsiDirectory.add(parentPsiDirectory);
          } else {
            selectPsiDirectory.add(directory);
          }
        }
      }
    }
    return selectPsiDirectory.stream().distinct().collect(Collectors.toList());
  }

  /**
   * 汉字转拼音
   * @param input 汉字
   * @return 汉字对应的拼音
   */
  public static String convertToPinyin(String input) {
    try {
      StringBuilder sb = new StringBuilder();
      HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
      format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
      for (char c : input.toCharArray()) {
        String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c, format);
        if (pinyinArray != null && pinyinArray.length > 0) {
          String pinyin = pinyinArray[0];
          sb.append(Character.toUpperCase(pinyin.charAt(0))).append(pinyin.substring(1));
        } else {
          sb.append(c);
        }
      }
      return SwingUi.removeSymbols(sb.toString());
    } catch (Exception e) {
      return null;
    }
  }
}
